package cn.z2huo.demo.data.generate.database.user;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.RandomUtil;
import cn.z2huo.core.enums.YesNoEnum;
import cn.z2huo.core.util.IdUtils;
import cn.z2huo.demo.data.generate.database.enums.company.ComCodeEnum;
import cn.z2huo.demo.data.generate.database.enums.company.ComFlagEnum;
import cn.z2huo.demo.data.generate.database.enums.company.ComLevelEnum;
import cn.z2huo.demo.data.generate.database.enums.company.ComTypeEnum;
import cn.z2huo.demo.data.generate.database.enums.user.RoamingTypeEnum;
import cn.z2huo.demo.data.generate.database.enums.user.SvrScopeEnum;
import cn.z2huo.demo.data.generate.database.enums.user.UserTypeEnum;
import cn.z2huo.demo.mapper.ccip.CcipUserPropertyMapper;
import cn.z2huo.demo.mapper.company.CompanyPropertyMapper;
import cn.z2huo.demo.model.dataobject.ccip.CcipUserPropertyDO;
import cn.z2huo.demo.model.dataobject.company.CompanyPropertyDO;
import com.baomidou.mybatisplus.core.batch.MybatisBatch;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <p>精简版，只生成财险用户数据，机构添加省公司
 *
 * @author z2huo
 */
@Component
@RequiredArgsConstructor
public class UserDataGenerator2 {

    /**
     * 需要生成数据的默认数据量
     */
    private static final int GENERATE_DATA_COUNT = 1_000_000;

    private static final List<String> SVR_SCOPE_VALUE_LIST = Arrays.stream(SvrScopeEnum.values()).map(SvrScopeEnum::getValue).toList();

    private static final List<String> USER_TYPE_VALUE_LIST = Arrays.stream(UserTypeEnum.values()).map(UserTypeEnum::getValue).toList();

    private static final List<String> ROAMIN_TYPE_VALUE_LIST = Arrays.stream(RoamingTypeEnum.values()).map(RoamingTypeEnum::getValue).toList();

    private final CcipUserPropertyMapper userMapper;

    private final CompanyPropertyMapper companyMapper;

    private final SqlSessionFactory sqlSessionFactory;

    /**
     * 根公司代码，包括总公司，省公司和中心
     */
    private final List<String> baseComCodeList = new ArrayList<>();

    /**
     * 根机构代码和机构代码的映射
     */
    private final Map<String, List<String>> companyMap = new HashMap<>();

    private final AtomicInteger userCodeInteger = new AtomicInteger(1);

    @PostConstruct
    public void init() {

        LambdaQueryWrapper<CompanyPropertyDO> baseCompanyQueryWrapper = Wrappers.lambdaQuery(CompanyPropertyDO.class);
        baseCompanyQueryWrapper.select(CompanyPropertyDO::getComCode)
                .eq(CompanyPropertyDO::getComLevel, ComLevelEnum.PROVINCIAL_COMPANY.getValue())
                .eq(CompanyPropertyDO::getComFlag, ComFlagEnum.ORGANIZATION.getValue())
                .eq(CompanyPropertyDO::getValidFlag, "1");
        baseComCodeList.addAll(companyMapper.selectList(baseCompanyQueryWrapper).stream().map(CompanyPropertyDO::getComCode).toList());

        for (String comCode : baseComCodeList) {
            companyMap.computeIfAbsent(comCode, baseComCode -> {
                LambdaQueryWrapper<CompanyPropertyDO> companyQueryWrapper = Wrappers.lambdaQuery(CompanyPropertyDO.class);
                companyQueryWrapper.select(CompanyPropertyDO::getComCode)
                        .eq(CompanyPropertyDO::getComFlag, ComFlagEnum.ORGANIZATION.getValue())
                        .eq(CompanyPropertyDO::getComType, ComTypeEnum.OUTBOUND.getValue())
                        .eq(CompanyPropertyDO::getValidFlag, YesNoEnum.YES.getValue())
                        .like(CompanyPropertyDO::getUpperPath, baseComCode);
                return companyMapper.selectList(companyQueryWrapper).stream().map(CompanyPropertyDO::getComCode).toList();
            });
        }

        baseComCodeList.add(ComCodeEnum.HEAD_QUARTERS.getValue());
        companyMap.put(ComCodeEnum.HEAD_QUARTERS.getValue(), List.of());
    }

    /**
     *
     * @param batchSizeEveryCompany 各个公司生成数量
     */
    public void generate(int batchSizeEveryCompany) {

        int companyCount = baseComCodeList.size();

        for (int i = 0; i < companyCount; i++) {
            String baseComCode = baseComCodeList.get(i);
            for (int j = 0; j < batchSizeEveryCompany; j++) {
                CcipUserPropertyDO ccipUserDO = generateUserDO(baseComCode);
                userMapper.insert(ccipUserDO);
            }
        }
    }

    /**
     *
     * @param batchSizeEveryCompany 每个公司生成数量
     * @param batchSize 每次向数据库中插入数据的数量
     */
    public void generateBatchInsert(int batchSizeEveryCompany, int batchSize) {
        // 公司数量
        int companyCount = baseComCodeList.size();
        for (int i = 0; i < companyCount; i++) {
            // 根公司代码
            String baseComCode = baseComCodeList.get(i);
            // 插入批次数
            int batchCount = batchSizeEveryCompany % batchSize == 0 ?
                    batchSizeEveryCompany / batchSize : batchSizeEveryCompany / batchSize + 1;
            for (int j = 0; j < batchCount; j++) {
                // 每一批次插入多少数据
                int size = i == batchCount - 1 ? batchSizeEveryCompany % batchSize : batchSize;
                List<CcipUserPropertyDO> userDOList = new ArrayList<>(size);
                for (int k = 0; k < size; k++) {
                    userDOList.add(generateUserDO(baseComCode));
                }
                this.batchInsert(userDOList);
            }
        }
    }

    private void batchInsert(List<CcipUserPropertyDO> userDOList) {
        MybatisBatch<CcipUserPropertyDO> ccipUserDOMybatisBatch = new MybatisBatch<CcipUserPropertyDO>(sqlSessionFactory, userDOList);
        MybatisBatch.Method<CcipUserPropertyDO> method = new MybatisBatch.Method<>(CcipUserPropertyMapper.class);
        ccipUserDOMybatisBatch.execute(method.insert());
    }

    private CcipUserPropertyDO generateUserDO(String baseComCode) {
        CcipUserPropertyDO ccipUserDO = new CcipUserPropertyDO();
        ccipUserDO.setId(IdUtils.nextId());
        ccipUserDO.setUserType(RandomUtil.randomEle(USER_TYPE_VALUE_LIST));
        ccipUserDO.setRoamingType(RandomUtil.randomEle(ROAMIN_TYPE_VALUE_LIST));

        ccipUserDO.setGroupUserCode(RandomUtil.randomNumbers(10));
        int nameLength = RandomUtil.randomInt(2, 4, true, true);
        StringBuilder sb = new StringBuilder();
        for (int j = 0; j < nameLength; j++) {
            sb.append(RandomUtil.randomChinese());
        }
        ccipUserDO.setUserName(sb.toString());

        ccipUserDO.setBaseComCode(baseComCode);
        List<String> companyCodeList = companyMap.get(baseComCode);
        String comCode = CollectionUtils.isEmpty(companyCodeList) ? baseComCode : RandomUtil.randomEle(companyCodeList);
        ccipUserDO.setComCode(comCode);
        ccipUserDO.setPComCode(comCode);

//        String userCode = RandomUtil.randomNumbers(8);
        String userCode = String.format("%08d", userCodeInteger.getAndIncrement());
        ccipUserDO.setNewUserCode(userCode);
        ccipUserDO.setOldUserCode(userCode);

        ccipUserDO.setValidStatus(YesNoEnum.YES.getValue());
        ccipUserDO.setRemark(RandomUtil.randomString(RandomUtil.randomInt(20, 80)));

        ccipUserDO.setSysSource(RandomUtil.randomEle(List.of("1", "2", "3")));

        ccipUserDO.setPGradeName(RandomUtil.randomString(RandomUtil.randomInt(10, 30)));
        DateTime dateTime = RandomUtil.randomDay(-3650, 0);
        ccipUserDO.setPGradeDate(dateTime.toLocalDateTime().toLocalDate());

        ccipUserDO.setUserSort("1");
        ccipUserDO.setCrossUserFlag("0");
        ccipUserDO.setRoamingStatus("0");

        ccipUserDO.setValidEndDate(RandomUtil.randomDay(365, 3650).toLocalDateTime().toLocalDate());

        ccipUserDO.setFlag("0");

        return ccipUserDO;
    }

}
